package org.hzero.interfaces.common.aspect;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.hzero.interfaces.common.annoations.KnifeInterfaceLog;
import org.hzero.interfaces.common.constants.KnifeInterfaceLogDirection;
import org.hzero.interfaces.common.entity.KnifeInterfaceLogRecord;
import org.hzero.interfaces.common.helper.KnifeInterfaceLogHelper;
import org.hzero.interfaces.common.helper.director.KnifeInterfaceLogDirector;
import org.hzero.interfaces.common.helper.impl.KnifeAopInterfaceLogHelperImpl;
import org.hzero.interfaces.common.utils.KnifeLogParamUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.MessageCodesResolver;

import javax.servlet.ServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;

/**
 * 1 controller接口,请求日志记录;配合{@link KnifeInterfaceLog}实现
 * 2 需要注入这个切面，切点为{@link KnifeInterfaceLog}
 *
 * @author: tianhao.luo@hand-china.com 2021/6/28  上午10:27
 */
@Component
@Order(100)
public class KnifeInterfaceLogAdvice implements MethodInterceptor {

    private static final Logger LOGGER = LoggerFactory.getLogger(KnifeInterfaceLogAdvice.class);

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        // 切点只能用于public类型的方法
        Method api = methodInvocation.getMethod();
        Object invoke = null;
        KnifeInterfaceLog knifeInterfaceLog = api.getAnnotation(KnifeInterfaceLog.class);
        if (knifeInterfaceLog != null && knifeInterfaceLog.value()) {
            Object[] arguments = methodInvocation.getArguments();
            // 深克隆方法参数，避免代理方法内修改导致记录的参数异常
            Map<String, Object> map = KnifeLogParamUtil.deepCloneArgs(arguments,
                    api.getParameters(),
                    ServletRequest.class,
                    BindingResult.class,
                    MessageCodesResolver.class);
            // 日志记录
            KnifeInterfaceLogRecord knifeInterfaceLogRecord = new KnifeInterfaceLogRecord(new Date(), KnifeInterfaceLogDirection.IN, knifeInterfaceLog.interfaceEnum());
            KnifeInterfaceLogHelper aopKnifeInterfaceLogHelper;
            try {
                invoke = methodInvocation.proceed();
                aopKnifeInterfaceLogHelper = new KnifeAopInterfaceLogHelperImpl(knifeInterfaceLogRecord, HttpStatus.OK);
                KnifeInterfaceLogDirector knifeInterfaceLogDirector = new KnifeInterfaceLogDirector(aopKnifeInterfaceLogHelper);
                knifeInterfaceLogDirector.createHitfInterfaceLog(map, invoke, api);
            } catch (Throwable throwable) {
                // 记录错误日志
                aopKnifeInterfaceLogHelper = new KnifeAopInterfaceLogHelperImpl(knifeInterfaceLogRecord, HttpStatus.INTERNAL_SERVER_ERROR, new Exception(throwable));
                KnifeInterfaceLogDirector knifeInterfaceLogDirector = new KnifeInterfaceLogDirector(aopKnifeInterfaceLogHelper);
                knifeInterfaceLogDirector.createHitfInterfaceLog(map, invoke, api);
                throw throwable;

            }
        } else {
            invoke = methodInvocation.proceed();
        }
        return invoke;
    }
}
